Skip to content

bhwi-cli: command to enumerate devices#18

Merged
edouardparis merged 3 commits intowizardsardine:mainfrom
trevarj:cli-enumerate
Mar 13, 2026
Merged

bhwi-cli: command to enumerate devices#18
edouardparis merged 3 commits intowizardsardine:mainfrom
trevarj:cli-enumerate

Conversation

@trevarj
Copy link
Copy Markdown
Collaborator

@trevarj trevarj commented Mar 10, 2026

The main goal of this change is to add a command to bhwi-cli that enumerates all
supported devices and displays information (ex. fingerprint) about them so that
the user can interact with a device.

Lots of tangential changes have also been made as I was trying to build out a
decent foundation for adding device enumeration.

Large refactors were done in order to make it possible to have heterogeneous
vectors of devices. It's not a major benefit but it makes the cli code nicer.
This includes the creation of the HWIDevice trait and making error types use
thiserror to implement std::error::Error. This also required the bhwi-wasm
errors to be changed from JsValue to a wrapper error, WasmError, which converts
the errors to strings. Not ideal, but could not find a better solution right
now.

Lots of the Transports from the e2e crates were moved around and changed for
re-usability between the cli crate e2e tests.

The rest of the changes were simply writing the Transports (HID and serial
backends) used for the currently supported devices.

trevarj added 2 commits March 9, 2026 11:56
…port

On Guix System, using guix shell, the C_INCLUDE_PATH remains set but is missing
the 32 bit headers. Unsetting it somehow allows cargo/cc to resolve things.
@trevarj trevarj requested a review from edouardparis March 11, 2026 07:56
@edouardparis edouardparis marked this pull request as ready for review March 11, 2026 09:18
Comment thread bhwi-async/src/lib.rs
// generate this trait by putting it over HWI's definition and then also
// generate the blanket impl which will map the errors to HWIDeviceError
#[async_trait(?Send)]
pub trait HWIDevice {
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Trying to come up with a better solution to this before attempting to write a proc macro. Duplicating all the methods isn't so awful, but not very nice IMO

Comment thread bhwi/src/common.rs Outdated
Comment thread bhwi-cli/src/bin/bhwi.rs Outdated
Comment thread bhwi-cli/src/lib.rs Outdated
@edouardparis
Copy link
Copy Markdown
Member

while compiling:

error[E0599]: no function or associated item named `from_utf8` found for type `str` in the current scope
   --> bhwi/src/jade/mod.rs:172:35
    |
172 |                     message: str::from_utf8(message)
    |                                   ^^^^^^^^^ function or associated item not found in `str`
    |
help: you are looking for the module in `std`, not the primitive type
    |
172 |                     message: std::str::from_utf8(message)
    |                              +++++

and after fixing, I tried running the list without any device.

cargo run -- device list
thread 'main' panicked at bhwi-cli/src/coldcard.rs:112:18:
couldn't connect to socket: Os { code: 2, kind: NotFound, message: "No such file or directory" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

@trevarj
Copy link
Copy Markdown
Collaborator Author

trevarj commented Mar 11, 2026

@edouardparis Thanks for trying it and reviewing! I got a bit lost in trying to create fancy futures stuff, that's why it crashes when it can't find a coldcard emulator.

message: str::from_utf8(message)

This is probably a rust version issue? It compiles for me on nightly. Perhaps I should start developing with stable.

Anyway, I resolved these issues so you can try again! bfbfe39

I think the flow of unlocking and setting the fingerprint is a little rough right now. Not sure on the best way to design that yet.

@edouardparis
Copy link
Copy Markdown
Member

Some trait do not need to have more rigid requirement to work with you implementation. I have bhwi-cli compiling with this diff:

git diff
diff --git a/bhwi-async/src/lib.rs b/bhwi-async/src/lib.rs
index 082762f..b5e33d2 100644
--- a/bhwi-async/src/lib.rs
+++ b/bhwi-async/src/lib.rs
@@ -20,19 +20,19 @@ pub use ledger::Ledger;

 #[async_trait(?Send)]
 pub trait Transport {
-    type Error: StdError + Send + Sync + Debug + 'static;
+    type Error;
     async fn exchange(&mut self, command: &[u8], encrypted: bool) -> Result<Vec<u8>, Self::Error>;
 }

 #[async_trait(?Send)]
 pub trait HttpClient {
-    type Error: StdError + Send + Sync + Debug + 'static;
+    type Error;
     async fn request(&self, url: &str, request: &[u8]) -> Result<Vec<u8>, Self::Error>;
 }

 #[async_trait(?Send)]
 pub trait HWI {
-    type Error: StdError + Send + Sync + Debug + 'static;
+    type Error;
     async fn unlock(&mut self, network: Network) -> Result<(), Self::Error>;
     async fn get_master_fingerprint(&mut self) -> Result<Fingerprint, Self::Error>;
     async fn get_extended_pubkey(
@@ -77,11 +77,7 @@ impl HWIDeviceError {
 }

 #[derive(Debug, thiserror::Error)]
-pub enum Error<E, F>
-where
-    E: StdError + Send + Sync + 'static,
-    F: StdError + Send + Sync + 'static,
-{
+pub enum Error<E, F> {
     #[error("transport error: {0}")]
     Transport(E),

@@ -202,8 +198,8 @@ pub trait OnUnlock {
 }

 pub trait CommonInterface<C, T, R, E> {
-    type TransportError: StdError + Send + Sync + Debug + 'static;
-    type HttpClientError: StdError + Send + Sync + Debug + 'static;
+    type TransportError;
+    type HttpClientError;

     #[allow(clippy::type_complexity)]
     fn components(
@@ -220,8 +216,6 @@ async fn run_command<D, C, E, F>(
     command: C,
 ) -> Result<common::Response, Error<E, F>>
 where
-    E: StdError + Send + Sync + std::fmt::Debug + 'static,
-    F: StdError + Send + Sync + std::fmt::Debug + 'static,
     D: CommonInterface<
             common::Command,
             common::Transmit,

For the implementation of HWIDevice we will see later how it goes, If you look at bhwi-wasm I directly used enum instead of trying to keep a special trait. Maybe this enum can be removed later in favor of the HWIDevice trait.

Comment thread bhwi-cli/src/bin/bhwi.rs Outdated
The main goal of this change is to add a command to bhwi-cli that enumerates all
supported devices and displays information (ex. fingerprint) about them so that
the user can interact with a device.

Lots of tangential changes have also been made as I was trying to build out a
decent foundation for adding device enumeration.

Large refactors were done in order to make it possible to have heterogeneous
vectors of devices. It's not a major benefit but it makes the cli code nicer.
This includes the creation of the HWIDevice trait and making error types use
thiserror to implement std::error::Error. This also required the bhwi-wasm
errors to be changed from JsValue to a wrapper error, WasmError, which converts
the errors to strings. Not ideal, but could not find a better solution right
now.

Lots of the Transports from the e2e crates were moved around and changed for
re-usability between the cli crate e2e tests.

The rest of the changes were simply writing the Transports (HID and serial
backends) used for the currently supported devices.
@trevarj
Copy link
Copy Markdown
Collaborator Author

trevarj commented Mar 13, 2026

Some trait do not need to have more rigid requirement to work with you implementation

This is true. Fixed.

@trevarj trevarj requested a review from edouardparis March 13, 2026 13:43
@edouardparis edouardparis merged commit 1791cbc into wizardsardine:main Mar 13, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants